package stattracker;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.TreeMap;

public class Halo3Stats implements java.io.Serializable 
{
	private static final String JABRONIE_MAN = "Jabronie Man";
	private static final String IPWN_ON_IPHONE = "iPwn on iPhone";
	private static final String STOCKER_EH = "Stocker eh";
	private static final int SERIOUS_250000 = 250000;
	private static final int THREE_THOUSAND = 3000;
	private static final int BEAST_ASSIST = 20;
	private static final int BEAST_KD = 20;
	private static final int MASSIVE_POSITIVE = 30;
	private static final int NINE_THOUSAND = 9000;
	private static final int CARRY_KILLS = 30;
	private static final int ASSASSINATIONS = 7;
	private static final int FIVE_MILLION = 5000000;
	private static final int ONE_BILLION = 1000000000;
	private static final long serialVersionUID = 1L;
	private Halo3Achievements achievements;
	private ArrayList<Halo3GameData> allGames, matchmadeGames, customGames, forgeGames;
	private ArrayList<Medal> allMedals, customMedals;
	private ArrayList<Weapon> allWeapons, customWeapons;
	private ArrayList<Playlist> playlists;
	private TreeMap<String, Integer> players;
	private ArrayList<String> sortedPlayers;
	private int totalKills, totalDeaths, totalAssists;
	private int customKills, customDeaths, customAssists;
	private int totalTime, customTime;
	private int sniperKills, sniperMedals, customSniperKills, customSniperMedals;
	private int stickyKills, stickyMedals, customStickyKills, customStickyMedals;
	private String gamertag;
	
	public Halo3Stats(String gamertag)
	{
		this.gamertag = gamertag;
		achievements = new Halo3Achievements();
		allGames = new ArrayList<Halo3GameData>();
		matchmadeGames = new ArrayList<Halo3GameData>();
		customGames = new ArrayList<Halo3GameData>();
		forgeGames = new ArrayList<Halo3GameData>();
		allMedals = new ArrayList<Medal>();
		customMedals = new ArrayList<Medal>();
		allWeapons = new ArrayList<Weapon>();
		customWeapons = new ArrayList<Weapon>();
		playlists = new ArrayList<Playlist>();
		players = new TreeMap<String, Integer>(); 
		sortedPlayers = new ArrayList<String>();
		zeroValues();
	}
	
	public double getSniperPercentage()
	{
		return ((double)sniperMedals / sniperKills) * 100;
	}
	
	public double getCustomSniperPercentage()
	{
		return ((double)customSniperMedals / customSniperKills) * 100;
	}
	
	public double getStickyPercentage()
	{
		return ((double)stickyMedals / stickyKills) * 100;
	}
	
	public double getCustomStickyPercentage()
	{
		return ((double)customStickyMedals / customStickyKills) * 100;
	}
	
	public int getTotalTime()
	{
		return totalTime;
	}
	
	public int getCustomTime()
	{
		return customTime;
	}
	
	public int getTotalKills()
	{
		return totalKills;
	}
	
	public int getTotalDeaths()
	{
		return totalDeaths;
	}
	
	public int getTotalAssists()
	{
		return totalAssists;
	}
	
	public int getCustomKills()
	{
		return customKills;
	}
	
	public int getCustomDeaths()
	{
		return customDeaths;
	}
	
	public int getCustomAssists()
	{
		return customAssists;
	}
	
	public ArrayList<Halo3GameData> getAllGames()
	{
		return allGames;
	}
	
	public ArrayList<Halo3GameData> getMatchmadeGames()
	{
		return matchmadeGames;
	}
	
	public ArrayList<Halo3GameData> getCustomGames()
	{
		return customGames;
	}
	
	public ArrayList<Halo3GameData> getForgeGames()
	{
		return forgeGames;
	}
	
	public ArrayList<Medal> getAllMedals()
	{
		return allMedals;
	}
	
	public ArrayList<Medal> getCustomMedals()
	{
		return customMedals;
	}
	
	public ArrayList<Weapon> getAllWeapons()
	{
		return allWeapons;
	}
	
	public ArrayList<Weapon> getCustomWeapons()
	{
		return customWeapons;
	}
	
	public ArrayList<Playlist> getPlaylists()
	{
		return playlists;
	}
	
	public Halo3Achievements getAchievements()
	{
		return achievements;
	}
	
	public TreeMap<String, Integer> getMappedPlayers()
	{
		return players;
	}
	
	public ArrayList<String> getSortedPlayers()
	{
		return sortedPlayers;
	}
	
	public void compileStats(TreeMap<Long, Halo3GameData> games)
	{
		clearLists();
		
		Collection<Halo3GameData> c = games.values();
		allGames = new ArrayList<Halo3GameData>(c);
		
		processGames();
	
		Collection<String> p = players.keySet();
		sortedPlayers = new ArrayList<String>(p);
		Collections.sort(sortedPlayers, new PlayerSorter(players));
		
		processPlaylists();
		
		checkAchievements();
	}
	
	private void processGames()
	{
		for(Halo3GameData g : allGames)
		{
			String timeSpent = g.getDetail().getLength();
			if(MyUtils.emptyString(timeSpent.trim()))
			{
				timeSpent = "00:08:00";
				g.getDetail().setLength(timeSpent);
			}
			totalTime += MyUtils.parseSec(timeSpent);
			if(g.getInfo().getPlaylist().equals("Custom Game"))
			{
				if(g.getInfo().getGameType().equals("Forge") || g.getInfo().getGameType().equals("Sandbox"))
				{
					forgeGames.add(g);
				}
				else
				{
					customGames.add(g);
					customTime += MyUtils.parseSec(g.getDetail().getLength());
					totalKills += g.getDetail().getKills();
					totalDeaths += g.getDetail().getDeaths();
					totalAssists += g.getDetail().getAssists();
					customKills += g.getDetail().getKills();
					customDeaths += g.getDetail().getDeaths();
					customAssists += g.getDetail().getAssists();
					processMedals(g, customMedals);
					processWeapons(g, customWeapons);
				}
			}
			else
			{
				matchmadeGames.add(g);
				totalKills += g.getDetail().getKills();
				totalDeaths += g.getDetail().getDeaths();
				totalAssists += g.getDetail().getAssists();
				if(!playListFound(g.getInfo().getPlaylist(), g.getDetail().isRanked()))
				{
					Playlist newList = new Playlist(g.getInfo().getPlaylist(), g.getDetail().isRanked());
					newList.addGame(g);
					playlists.add(newList);
				}
				else
					addGameToPlaylist(g);
			}
			
			processMedals(g, allMedals);
			processWeapons(g, allWeapons);
			
			processPlayers(g.getDetail().getOtherGamers());
		}
		Collections.sort(allWeapons);
		Collections.sort(customWeapons);

		calculateTotalPercentages();
		calculateCustomPercentages();
	}
	
	private void processPlayers(ArrayList<String> playedWith)
	{
		for(String s : playedWith)
		{
			if(!s.equals(gamertag))
			{
				if(players.containsKey(s))
				{
					Integer curr = players.get(s);
					curr = new Integer(curr.intValue() + 1);
					players.put(s, curr);
				}
				else
				{
					players.put(s, new Integer(1));
				}
			}
		}
	}
	
	private void calculateTotalPercentages()
	{
		for(Weapon w : allWeapons)
		{
			if(w.getName().contains("Sniper") || w.getName().contains("Beam Rifle"))
				sniperKills += w.getKillCount();
			if(w.getName().contains("Plasma Grenade") || w.getName().contains("Spike Grenade"))
				stickyKills += w.getKillCount();
		}
		
		for(Medal m : allMedals)
		{
			if(m.getName().contains("Sniper Kill"))
				sniperMedals = m.getMedalCount();
			if(m.getName().contains("Stick"))
				stickyMedals = m.getMedalCount();
		}
	}
	
	private void calculateCustomPercentages()
	{
		for(Weapon w : customWeapons)
		{
			if(w.getName().contains("Sniper") || w.getName().contains("Beam Rifle"))
				customSniperKills += w.getKillCount();
			if(w.getName().contains("Plasma Grenade") || w.getName().contains("Spike Grenade"))
				customStickyKills += w.getKillCount();
		}
		
		for(Medal m : customMedals)
		{
			if(m.getName().contains("Sniper Kill"))
				customSniperMedals = m.getMedalCount();
			if(m.getName().contains("Stick"))
				customStickyMedals = m.getMedalCount();
		}
	}
	
	private void processMedals(Halo3GameData g, ArrayList<Medal> cummulate)
	{
		for(Medal m : g.getDetail().getMedals())
		{
			for(Medal c : cummulate)
			{
				if(m.getName().equals(c.getName()))
				{
					c.setMedalCount(c.getMedalCount() + m.getMedalCount());
				}
			}
		}
	}
	
	private void processWeapons(Halo3GameData g, ArrayList<Weapon> cummulate)
	{
		for(Weapon w : g.getDetail().getWeapons())
		{
			for(Weapon c : cummulate)
			{
				if(w.getName().equals(c.getName()))
				{
					c.setKillCount(c.getKillCount() + w.getKillCount());
				}
			}
		}
	}
	
	private void addGameToPlaylist(Halo3GameData g)
	{
		for(Playlist p : playlists)
		{
			if(p.getTitle().equals(g.getInfo().getPlaylist()) && p.isRanked() == g.getDetail().isRanked())
			{
				p.addGame(g);
				return; //no need to continue looping through everything
			}
		}
	}
	
	private void processPlaylists()
	{
		Collections.sort(playlists);
		for(Playlist p : playlists)
		{
			p.compileStatistics();
		}
	}
	
	private boolean playListFound(String title, boolean ranked)
	{
		for(Playlist p : playlists)
		{
			if(p.getTitle().equals(title) && ranked == p.isRanked())
				return true;
		}
		return false;
	}
	
	private void updateAchievements()
	{
		//TODO Comment the clearing out
		achievements.getAchievements().clear();
		Halo3Achievements curr = new Halo3Achievements();
		for(String key : curr.getAchievements().keySet())
		{
			if(!achievements.hasAchievement(key))
			{
				achievements.addNewAchievement(curr.getAchievements().get(key));
			}
		}
	}
	
	private void checkAchievements()
	{
		//TODO Genetically Different Achievement, How many games have they quit out of?
		updateAchievements();
		int tempKills = 0;
		int mlgExterm = 0;
		int steak = 0;
		String firstExtermURL = "";
		String tenthExtermURL = "";
		if(!achievements.got(Halo3Achievements.ITS_OVER_9000) && allGames.size() > NINE_THOUSAND)
			achievements.unlock(Halo3Achievements.ITS_OVER_9000, allGames.get(NINE_THOUSAND - 1).getInfo().getURL());
		for(Halo3GameData g : allGames)
		{
			if(!achievements.got(Halo3Achievements.SERIOUSLY_SERIOUS)) //unlocks 'Seriously?! Serious.'
			{
				tempKills += g.getDetail().getKills();
				if(tempKills >= SERIOUS_250000)
				{
					achievements.unlock(Halo3Achievements.SERIOUSLY_SERIOUS, g.getInfo().getURL());
				}
			}
			if(g.getInfo().getPlaylist().contains("MLG")) 
			{
				for(Medal m : g.getDetail().getMedals())
				{
					if(m.getName().contains("Extermination")) //Does work for 'Four Down' and 'Pest Control'
					{
						mlgExterm += m.getMedalCount();
						if(mlgExterm >= 1)
							firstExtermURL = g.getInfo().getURL();
						if(mlgExterm >= 10)
							tenthExtermURL = g.getInfo().getURL();
					}
					if(!achievements.got(Halo3Achievements.SNEAKY_BEAVER) && m.getName().contains("Assassination")) 
					{
						if(m.getMedalCount() >= ASSASSINATIONS)
							achievements.unlock(Halo3Achievements.SNEAKY_BEAVER, g.getInfo().getURL());
					}
					if(!achievements.got(Halo3Achievements.WAIT_HOW_MANY_ARE_ON_A_TEAM))
					{
						if(m.getImgLoc().contains("Multikill") && m.getDifficulty() > 5 && !m.getName().contains("Extermination"))
						{
							achievements.unlock(Halo3Achievements.WAIT_HOW_MANY_ARE_ON_A_TEAM, g.getInfo().getURL());
						}
					}
				}
				if(!achievements.got(Halo3Achievements.OUCH_MY_BACK_HURTS) && g.getDetail().getKills() >= CARRY_KILLS && g.getInfo().getGameType().contains("Slayer"))
					achievements.unlock(Halo3Achievements.OUCH_MY_BACK_HURTS, g.getInfo().getURL());
			}
			if(!g.getInfo().getPlaylist().contains("Custom"))  //for matchmaking only achievements
			{
				if(!achievements.got(Halo3Achievements.DID_THEY_QUIT) && (g.getDetail().getKills() - g.getDetail().getDeaths()) >= MASSIVE_POSITIVE) //Unlocks 'Did They Quit?'
					achievements.unlock(Halo3Achievements.DID_THEY_QUIT, g.getInfo().getURL());
				if(!achievements.got(Halo3Achievements.CANT_PLAY_TOO_FULL)) //going to check for Steak
				{
					boolean foundSteak = false;
					for(Medal m : g.getDetail().getMedals())
					{
						if(m.getName().contains("Steak"))
						{
							foundSteak = true;
							steak++;
							if(steak == 5)
								achievements.unlock(Halo3Achievements.CANT_PLAY_TOO_FULL, g.getInfo().getURL());
						}
					}
					if(!foundSteak)
						steak = 0;
				}
				if(!achievements.got(Halo3Achievements.BEAST_MODE_ACTIVATE) && (g.getDetail().getKills() - g.getDetail().getDeaths()) >= BEAST_KD && g.getDetail().getAssists() >= BEAST_ASSIST) 
					achievements.unlock(Halo3Achievements.BEAST_MODE_ACTIVATE, g.getInfo().getURL());
				if(!achievements.got(Halo3Achievements.CANT_TOUCH_THIS) && g.getDetail().isRanked()) // checking for 'Can't Touch This'
				{
					for(Medal m : g.getDetail().getMedals())
					{
						if(m.getName().contains("Invincible"))  //unlocks 'Can't Touch This'
							achievements.unlock(Halo3Achievements.CANT_TOUCH_THIS, g.getInfo().getURL());
					}
				}
				if(!achievements.got(Halo3Achievements.ANTI_PERFECTION)) //For 'Anti-Perfection'
				{
					if(g.getDetail().getKills() == 0 && g.getDetail().getDeaths() >= 15)
						achievements.unlock(Halo3Achievements.ANTI_PERFECTION, g.getInfo().getURL());
				}
				if(!achievements.got(Halo3Achievements.GUNS_DONT_KILL) && g.getDetail().isRanked() && g.getDetail().getKills() > 5
						&& !g.getInfo().getGameType().contains("Swords") && !g.getInfo().getGameType().contains("Hammers"))
				{
					if(g.getInfo().getPlacement().equals("1st"))
					{
						boolean failed = false;
						for(Weapon w : g.getDetail().getWeapons())
						{
							if(!w.getName().contains("Grenade") || !w.getName().contains("Melee")
									|| !w.getName().contains("Guardians") || !w.getName().contains("Explosion")
									|| !w.getName().contains("Classified"))
							{
								failed = true;
							}
						}
						if(!failed)
							achievements.unlock(Halo3Achievements.GUNS_DONT_KILL, g.getInfo().getURL());
					}
				}
				if(!achievements.got(Halo3Achievements.I_GOT_YOUR_SIX) && g.getDetail().getAssists() > 35) //For 'I got your six
					achievements.unlock(Halo3Achievements.I_GOT_YOUR_SIX, g.getInfo().getURL());
				
				if(!achievements.got(Halo3Achievements.EH_TU_BRUTE) && !g.getInfo().getPlaylist().contains("Grifball") 
						&& !g.getInfo().getPlaylist().contains("SWAT") && g.getDetail().getBetrayals() >= 8) //For 'Eh Tu Brute?'
					achievements.unlock(Halo3Achievements.EH_TU_BRUTE, g.getInfo().getURL());
			}
			//Check to see if you've played with VIP
			if(!achievements.got(Halo3Achievements.WHO_IS_STOCKER_EH))
			{
				if(g.getDetail().getOtherGamers().contains(STOCKER_EH))
				{
					achievements.unlock(Halo3Achievements.WHO_IS_STOCKER_EH, g.getInfo().getURL());
				}
			}
			if(!achievements.got(Halo3Achievements.DOES_HE_EVEN_HAVE_AN_IPHONE))
			{
				if(g.getDetail().getOtherGamers().contains(IPWN_ON_IPHONE))
				{
					achievements.unlock(Halo3Achievements.DOES_HE_EVEN_HAVE_AN_IPHONE, g.getInfo().getURL());
				}
			}
			if(!achievements.got(Halo3Achievements.WHATS_A_JABRONIE))
			{
				if(g.getDetail().getOtherGamers().contains(JABRONIE_MAN))
				{
					achievements.unlock(Halo3Achievements.WHATS_A_JABRONIE, g.getInfo().getURL());
				}
			}
			if(!achievements.got(Halo3Achievements.THE_DEVELOPERS))
			{
				ArrayList<String> others = g.getDetail().getOtherGamers();
				if(others.contains(JABRONIE_MAN) &&
					others.contains(IPWN_ON_IPHONE) &&
					others.contains(STOCKER_EH))
				{
					achievements.unlock(Halo3Achievements.THE_DEVELOPERS, g.getInfo().getURL());
				}
			}
		}
		if(mlgExterm >= 1) //Unlocks 'Four Down' and 'Pest Control'
		{
			if(!achievements.got(Halo3Achievements.FOUR_DOWN))
				achievements.unlock(Halo3Achievements.FOUR_DOWN, firstExtermURL);
			if(!achievements.got(Halo3Achievements.PEST_CONTROL) && mlgExterm >= 10)
				achievements.unlock(Halo3Achievements.PEST_CONTROL, tenthExtermURL);
		}
		if(!achievements.got(Halo3Achievements.I_CANT_QUIT_YOU))
		{
			if(allGames.size() > THREE_THOUSAND)
			{
				if(allGames.get(0).getID() <= FIVE_MILLION && allGames.get(allGames.size()-1).getID() <= ONE_BILLION)
				{
					achievements.unlock(Halo3Achievements.I_CANT_QUIT_YOU, "");
				}
			}
		}
	}
	
	private void clearLists()
	{
		allGames.clear();
		matchmadeGames.clear();
		customGames.clear();
		forgeGames.clear();
		playlists.clear();
		
		allMedals.clear();
		customMedals.clear();
		allWeapons.clear();
		customWeapons.clear();
		players.clear();
		MedalListUpdater medHelper = new MedalListUpdater();
		WeaponListUpdater wepHelper = new WeaponListUpdater();
		allMedals = medHelper.getMedalList();
		customMedals = medHelper.getMedalList();
		allWeapons = wepHelper.getWeapList();
		customWeapons = wepHelper.getWeapList();
		
		zeroValues();
	}
	
	private void zeroValues()
	{
		totalKills = 0; totalDeaths = 0; totalAssists = 0;
		customKills = 0; customDeaths = 0; customAssists = 0;
		totalTime = 0; customTime = 0;
		sniperKills = 0; sniperMedals = 0; customSniperKills = 0; customSniperMedals = 0;
		stickyKills = 0; stickyMedals = 0; customStickyKills = 0; customStickyMedals = 0;
	}
	
	public int allPlayed()
	{
		return allGames.size();
	}
	
	public int matchPlayed()
	{
		return matchmadeGames.size();
	}
	
	public int forgePlayed()
	{
		return forgeGames.size();
	}
	
	public int customsPlayed()
	{
		return customGames.size();
	}
}
class PlayerSorter implements Comparator<String>
{
	TreeMap<String, Integer> popularity;
	public PlayerSorter(TreeMap<String, Integer> pop)
	{
		popularity = pop;
	}
	
	public int compare(String o1, String o2) 
	{
		return popularity.get(o2).compareTo(popularity.get(o1));
	}	
}
